#include "stdafx.h"
#include "View.h"
#include "Container.h"

View::View()
: m_hNormal(0)
, m_hHighlight(0)
, m_hMouseDown(0)
, m_bTransparent(0)
, m_bValid(0)
{
	m_location.x = 0;
	m_location.y = 0;
	m_sz.cx = 0;
	m_sz.cy = 0;
	m_alpha = 0;
	m_bHover = false;
	m_dwLstCount = 0;
	m_bMouseDown = false;
	m_bMouseUpping = false;
	m_bMouseLeaving = false;

	memset(&m_rc9Gird, 0, sizeof(m_rc9Gird));
}

View::~View()
{
	if (m_hNormal)
		DeleteObject(m_hNormal);

	if (m_hHighlight)
		DeleteObject(m_hHighlight);

	if (m_hMouseDown)
		DeleteObject(m_hMouseDown);
}

void View::Click( const POINT* pt )
{

}

void View::MouseEnter()
{

}

void View::MouseLeave()
{

}
class CRect : public RECT
{
public:
	// Constructors
	CRect()
	{
		left = 0;
		top = 0;
		right = 0;
		bottom = 0;
	}

	CRect(int l, int t, int r, int b)
	{
		left = l;
		top = t;
		right = r;
		bottom = b;
	}

	int Width() const
	{
		return right - left;
	}

	int Height() const
	{
		return bottom - top;
	}
};

bool InternalGet9Grid(const RECT * lprcTarget, const RECT * lprcGrid, RECT * lprc9)
{
	lprc9[0] = CRect(lprcTarget->left, lprcTarget->top , lprcTarget->left + lprcGrid->left, lprcTarget->top + lprcGrid->top);
	lprc9[1] = CRect(lprcTarget->left + lprcGrid->left, lprcTarget->top, lprcTarget->right - lprcGrid->right, lprcTarget->top + lprcGrid->top);
	lprc9[2] = CRect(lprcTarget->right - lprcGrid->right, lprcTarget->top, lprcTarget->right, lprcTarget->top + lprcGrid->top);

	lprc9[3] = CRect(lprcTarget->left, lprcTarget->top + lprcGrid->top, lprcTarget->left + lprcGrid->left, lprcTarget->bottom - lprcGrid->bottom);
	lprc9[4] = CRect(lprcTarget->left + lprcGrid->left, lprcTarget->top + lprcGrid->top, lprcTarget->right - lprcGrid->right, lprcTarget->bottom - lprcGrid->bottom);
	lprc9[5] = CRect(lprcTarget->right - lprcGrid->right, lprcTarget->top + lprcGrid->top, lprcTarget->right, lprcTarget->bottom - lprcGrid->bottom);

	lprc9[6] = CRect(lprcTarget->left, lprcTarget->bottom - lprcGrid->bottom, lprcTarget->left + lprcGrid->left, lprcTarget->bottom);
	lprc9[7] = CRect(lprcTarget->left + lprcGrid->left, lprcTarget->bottom - lprcGrid->bottom, lprcTarget->right - lprcGrid->right, lprcTarget->bottom);
	lprc9[8] = CRect(lprcTarget->right - lprcGrid->right, lprcTarget->bottom - lprcGrid->bottom, lprcTarget->right, lprcTarget->bottom);

	return true;
}

void View::Render(HDC hdc, const RECT *lpRect)
{
	BITMAP bm = {0};
	GetObject(m_hNormal, sizeof(bm), &bm);
	RECT rcImage = {0, 0, bm.bmWidth, bm.bmHeight};
	RECT rcTarget = {m_location.x, m_location.y, m_location.x+m_sz.cx, m_location.y+m_sz.cy};

	CRect rcSrc[9];
	CRect rcDst[9];

	InternalGet9Grid(&rcImage, &m_rc9Gird, rcSrc);
	InternalGet9Grid(&rcTarget, &m_rc9Gird, rcDst);

	if (0) {
	}
	else if (m_bMouseUpping && m_hMouseDown) {
		{
			HDC hTemp = CreateCompatibleDC(hdc);
			HGDIOBJ hOldObj = SelectObject(hTemp, m_hNormal);

			BLENDFUNCTION bf;
			bf.BlendOp = AC_SRC_OVER;
			bf.BlendFlags = 0;
			bf.SourceConstantAlpha = (int)m_alpha;
			bf.AlphaFormat = 1;

			for (int i = 0; i < 9; ++i) {
				::AlphaBlend(hdc, rcDst[i].left, rcDst[i].top, rcDst[i].Width(), rcDst[i].Height(),
					hTemp, rcSrc[i].left, rcSrc[i].top, rcSrc[i].Width(), rcSrc[i].Height(), bf);
			}

			SelectObject(hTemp, hOldObj);
			DeleteObject(hTemp);
		}

		{
			HDC hTemp = CreateCompatibleDC(hdc);
			HGDIOBJ hOldObj = SelectObject(hTemp, m_hMouseDown);

			BLENDFUNCTION bf;
			bf.BlendOp = AC_SRC_OVER;
			bf.BlendFlags = 0;
			bf.SourceConstantAlpha = 255-(int)m_alpha;
			bf.AlphaFormat = 1;

			for (int i = 0; i < 9; ++i) {
				::AlphaBlend(hdc, rcDst[i].left, rcDst[i].top, rcDst[i].Width(), rcDst[i].Height(),
					hTemp, rcSrc[i].left, rcSrc[i].top, rcSrc[i].Width(), rcSrc[i].Height(), bf);
			}

			SelectObject(hTemp, hOldObj);
			DeleteObject(hTemp);
		}
	}
	else if (m_bMouseDown && m_hMouseDown) {

		HDC hTemp = CreateCompatibleDC(hdc);
		HGDIOBJ hOldObj = SelectObject(hTemp, m_hMouseDown);

		BLENDFUNCTION bf;
		bf.BlendOp = AC_SRC_OVER;
		bf.BlendFlags = 0;
		bf.SourceConstantAlpha = 255;
		bf.AlphaFormat = 1;

		for (int i = 0; i < 9; ++i) {
			::AlphaBlend(hdc, rcDst[i].left, rcDst[i].top, rcDst[i].Width(), rcDst[i].Height(),
				hTemp, rcSrc[i].left, rcSrc[i].top, rcSrc[i].Width(), rcSrc[i].Height(), bf);
		}

		SelectObject(hTemp, hOldObj);
		DeleteObject(hTemp);
	}	

	else if (m_bHover && m_hHighlight) {
		{
			HDC hTemp = CreateCompatibleDC(hdc);
			HGDIOBJ hOldObj = SelectObject(hTemp, m_hNormal);

			BLENDFUNCTION bf;
			bf.BlendOp = AC_SRC_OVER;
			bf.BlendFlags = 0;
			bf.SourceConstantAlpha = 255-(int)m_alpha;
			bf.AlphaFormat = 1;

			for (int i = 0; i < 9; ++i) {
				::AlphaBlend(hdc, rcDst[i].left, rcDst[i].top, rcDst[i].Width(), rcDst[i].Height(),
					hTemp, rcSrc[i].left, rcSrc[i].top, rcSrc[i].Width(), rcSrc[i].Height(), bf);
			}

			SelectObject(hTemp, hOldObj);
			DeleteObject(hTemp);
		}

		{
			HDC hTemp = CreateCompatibleDC(hdc);
			HGDIOBJ hOldObj = SelectObject(hTemp, m_hHighlight);

			BLENDFUNCTION bf;
			bf.BlendOp = AC_SRC_OVER;
			bf.BlendFlags = 0;
			bf.SourceConstantAlpha = (int)m_alpha;
			bf.AlphaFormat = 1;

			for (int i = 0; i < 9; ++i) {
				::AlphaBlend(hdc, rcDst[i].left, rcDst[i].top, rcDst[i].Width(), rcDst[i].Height(),
					hTemp, rcSrc[i].left, rcSrc[i].top, rcSrc[i].Width(), rcSrc[i].Height(), bf);
			}

			SelectObject(hTemp, hOldObj);
			DeleteObject(hTemp);
		}
	}

	else if (m_bMouseLeaving && m_hHighlight) {
		{
			HDC hTemp = CreateCompatibleDC(hdc);
			HGDIOBJ hOldObj = SelectObject(hTemp, m_hNormal);

			BLENDFUNCTION bf;
			bf.BlendOp = AC_SRC_OVER;
			bf.BlendFlags = 0;
			bf.SourceConstantAlpha = 255-(int)m_alpha;
			bf.AlphaFormat = 1;

			for (int i = 0; i < 9; ++i) {
				::AlphaBlend(hdc, rcDst[i].left, rcDst[i].top, rcDst[i].Width(), rcDst[i].Height(),
					hTemp, rcSrc[i].left, rcSrc[i].top, rcSrc[i].Width(), rcSrc[i].Height(), bf);
			}

			SelectObject(hTemp, hOldObj);
			DeleteObject(hTemp);
		}

		{
			HDC hTemp = CreateCompatibleDC(hdc);
			HGDIOBJ hOldObj = SelectObject(hTemp, m_hHighlight);

			BLENDFUNCTION bf;
			bf.BlendOp = AC_SRC_OVER;
			bf.BlendFlags = 0;
			bf.SourceConstantAlpha = (int)m_alpha;
			bf.AlphaFormat = 1;

			for (int i = 0; i < 9; ++i) {
				::AlphaBlend(hdc, rcDst[i].left, rcDst[i].top, rcDst[i].Width(), rcDst[i].Height(),
					hTemp, rcSrc[i].left, rcSrc[i].top, rcSrc[i].Width(), rcSrc[i].Height(), bf);
			}

			SelectObject(hTemp, hOldObj);
			DeleteObject(hTemp);
		}
	}
	else if (m_hNormal)
	{
		HDC hTemp = CreateCompatibleDC(hdc);
		HGDIOBJ hOldObj = SelectObject(hTemp, m_hNormal);

		BLENDFUNCTION bf;
		bf.BlendOp = AC_SRC_OVER;
		bf.BlendFlags = 0;
		bf.SourceConstantAlpha = 255;
		bf.AlphaFormat = 1;

		for (int i = 0; i < 9; ++i) {
			::AlphaBlend(hdc, rcDst[i].left, rcDst[i].top, rcDst[i].Width(), rcDst[i].Height(),
				hTemp, rcSrc[i].left, rcSrc[i].top, rcSrc[i].Width(), rcSrc[i].Height(), bf);
		}

		SelectObject(hTemp, hOldObj);
		DeleteObject(hTemp);
	}

	for (ViewLst::iterator it = m_vecChild.begin(); it != m_vecChild.end(); ++it) {
		TXCComPtr<View> pView = *it;
		POINT ptOld = {0};
		GetWindowOrgEx(hdc, &ptOld);
		SetWindowOrgEx(hdc, -(m_location.x-ptOld.x), -(m_location.y-ptOld.y), &ptOld);
		pView->Render(hdc, lpRect);
		SetWindowOrgEx(hdc, ptOld.x, ptOld.y, &ptOld);
	}
}

void View::DoClick( const POINT* pt )
{

}

void View::DoMouseEnter()
{
	m_bHover = true;
	m_dwLstCount = GetTickCount();
	if (m_hHighlight)
		Container::SetTimer(this, 10);
	OutputDebugString(L"DoMouseEnter\n");
}

void View::DoMouseLeave()
{
	m_bHover = false;
	m_dwLstCount = GetTickCount();
	if (m_hHighlight)
		Container::SetTimer(this, 10);
	OutputDebugString(L"DoMouseLeave\n");
	m_bMouseLeaving = true;
}

void View::SetSize( const SIZE * pSize )
{
	m_sz = *pSize;
}

void View::SetPos( const POINT * pPos )
{
	m_location = *pPos;
}

void View::DoMouseMove( const POINT* pt )
{

}

void View::ChildHitTest( const POINT *lpPoint, View** ppView )
{
	if (m_bTransparent)
		return;

	for (ViewLst::iterator it = m_vecChild.begin(); it != m_vecChild.end(); ++it) {
		RECT rect = {0};
		TXCComPtr<View> pView = *it;
		pView->GetRect(&rect);
		if (!m_bTransparent &&
			lpPoint->x >= rect.left && 
			lpPoint->x < rect.right &&
			lpPoint->y >= rect.top && 
			lpPoint->y < rect.bottom) {

				POINT pt = *lpPoint;
				pt.x -= rect.left;
				pt.y -= rect.top;
				pView->ChildHitTest(&pt, ppView);
				if (*ppView)
					return;
		}
	}

	(*ppView) = this;
	if ((*ppView)) {
		(*ppView)->addref();
	}
}

void View::GetRect( RECT *pRect )
{
	pRect->left = m_location.x;
	pRect->top = m_location.y;
	pRect->right = pRect->left+m_sz.cx;
	pRect->bottom = pRect->top+m_sz.cy;
}

void View::SetTexture(const wchar_t * pNormal, const wchar_t *pHighlight, const wchar_t *pMouseDown)
{
	if (m_hNormal) {
		DeleteObject(m_hNormal);
		m_hNormal = NULL;
	}
	if (pNormal) {
		m_hNormal = CreateTextureFromFile(pNormal);

		BITMAP bm = {0};
		GetObject(m_hNormal, sizeof(bm), &bm);
		if (m_sz.cx == 0 || m_sz.cy == 0) {
			SIZE sz = {bm.bmWidth, bm.bmHeight};
			SetSize(&sz);
		}		
	}

	if (m_hHighlight) {
		DeleteObject(m_hHighlight);
		m_hHighlight = NULL;
	}
	if (pHighlight)
		m_hHighlight = CreateTextureFromFile(pHighlight);		

	if (m_hMouseDown) {
		DeleteObject(m_hMouseDown);
		m_hMouseDown = NULL;
	}
	if (pMouseDown)
		m_hMouseDown = CreateTextureFromFile(pMouseDown);	
}

void View::AddChild(View* pObj )
{
	TXCComPtr<View> pView = pObj;
	m_vecChild.push_back(pView);

	pObj->m_pParent = this;
}

void View::Timer( void *id )
{	
	DWORD dwThsCount = GetTickCount();
	float fDetal = (float)dwThsCount-m_dwLstCount;

	if (m_bMouseUpping) {
		m_alpha += fDetal*1.0f;
		OutputDebugString(L"m_bMouseUpping\n");
		if (m_alpha > 255) {
			m_alpha = 0;
			m_bMouseUpping = false;
			Container::KillTimer(this);
		}
	}
	else {
		if (m_bHover)
			m_alpha += fDetal*1.0f;
		else if (m_bMouseLeaving)
			m_alpha -= fDetal*1.0f;	

		if (m_bHover && m_alpha > 255) {
			m_alpha = 255;
			Container::KillTimer(this);
		}

		if (m_bMouseLeaving && m_alpha < 0) {
			m_alpha = 0;
			m_bMouseLeaving = false;
			Container::KillTimer(this);
		}
	}

	m_dwLstCount = dwThsCount;

	InvalidateRect(NULL);
}

void View::InvalidateRect( const RECT *lpRect )
{
	if (m_pParent) {
		m_pParent->InvalidateRect(lpRect);
	}
	JGFireEvent(OnInvalidateRectFunc, OnInvalidateRect, (lpRect));
}

void View::DoTimer(void *id, bool & bFind)
{
	if ((const View*)id == this) {
		bFind = true;
		Timer(id);
		return;
	}

	for (ViewLst::iterator it = m_vecChild.begin(); it != m_vecChild.end(); ++it) {
		if (!bFind) {
			TXCComPtr<View> pView = *it;
			pView->DoTimer(id, bFind);
		}
	}
}

void View::Set9Gird( const RECT *lpRect )
{
	m_rc9Gird = *lpRect;
}

void View::DoMouseLeftDown(const POINT* pt)
{
	InvalidateRect(NULL);
	m_bMouseDown = true;
	m_alpha = 0;
}

void View::DoMouseLeftUp(const POINT* pt)
{
	InvalidateRect(NULL);
	m_bMouseDown = false;
	m_bMouseUpping = true;
	m_dwLstCount = GetTickCount();
	if (m_hMouseDown)
		Container::SetTimer(this, 10);
}

void View::DoSizeChange( const SIZE *pSize )
{

}

void View::GetSize( SIZE *pSize )
{
	*pSize = m_sz;
}

void View::GetPos( POINT *pPos )
{
	*pPos = m_location;
}

bool View::Create( View *pParent )
{
	if (pParent)
		pParent->AddChild(this);

	m_bValid = true;
	return m_bValid;
}

bool View::Destroy()
{
	if (!IsValid())
		return false;

	for (ViewLst::iterator it = m_vecChild.begin(); it != m_vecChild.end(); ++it) {
		TXCComPtr<View> pView = *it;
		pView->Destroy();
	}

	m_vecChild.clear();
	m_bValid = false;
	return true;
}

bool View::IsValid()
{
	return m_bValid;
}

void View::SetToolTips( const wchar_t *pTips )
{
	
}